# To change this template, choose Tools | Templates
# and open the template in the editor.
require 'matrix'

class RidgeRegression

  attr_accessor :weight,:lambda

  def initialize(train_matrix, train_vector, lambda=0.5)

    @lambda= lambda
    @weight= self.weight_train(train_matrix, train_vector, lambda)
    
  end
  def lambda
    @lambda
  end
  def weight
    @weight
  end
  # Update secondo i nuovi dati DA TESTARE!!!!!
  def update(train_matrix, train_vector)
    uweight= self.weight_train(train_matrix, train_vector, lambda=0.5)

    if self.weight.row_size==uweight.row_size then
      v= []
      (0..uweight.row_size-1).each{|i|
      v.push((uweight[i,0]+self.weight[i,0])/2)
      }
    end

    self.weight=Matrix[v].transpose
  end
  def weight_train(matrix_x,vector_y,lambda=self.lambda)
    trasposta= Matrix.columns(matrix_x).transpose
    trasp_molt= trasposta*Matrix.columns(matrix_x)    

    weight_vector= ((((trasp_molt) + lambda*Matrix.I(trasp_molt.row_size)).inverse))*trasposta*Matrix.column_vector(vector_y)
    
    return weight_vector
  end
  # Applica la regressione di ridge. input: matrice dei predittore, output: vettore di predizione
  def regressione(matrix_x)

    vector_y= Matrix.columns(matrix_x)*self.weight
    rounded_vector_y= []
    (0..vector_y.row_size-1).each { |i| rounded_vector_y.push(vector_y[i,0].round)  }

    return rounded_vector_y
  end
    def RidgeRegression.test()
    x = [[71,73,64,65,61,70,65,72,63,67,64]]
    y = [160,183,154, 168, 159, 180, 145, 210, 132, 168, 141]

    r= RidgeRegression.new(x,y)

    p '<---------------------------->'
    p 'Test ridge regression'
    p '<--------->'
    p 'Dati'
    p 'vettore dei pesi'
    p r.weight
    p 'scarto'
    p r.lambda
    p 'fine dati'
    p '<--------->'
    p 'test con valore 70'
    p 'valore atteso: [176.51,185]'
    p r.regressione([[70,72]])
    p '<---------------------------->'
  end
end
